/**
 * 图片懒加载指令
 * 性能优化：延迟加载不在视窗内的图片，减少初始加载时间
 */

import { App } from 'vue'

interface LazyOptions {
  // 预加载距离（距离视窗多少像素时开始加载）
  rootMargin?: string
  // 加载失败时的占位图
  error?: string
  // 加载中的占位图
  loading?: string
  // 尝试次数
  attempts?: number
}

export default {
  install(app: App, options: LazyOptions = {}) {
    const defaultOptions = {
      rootMargin: '50px',
      error: '/images/placeholder-error.png',
      loading: '/images/placeholder-loading.png',
      attempts: 3,
      ...options,
    }

    // 图片缓存，避免重复监听
    const imageCache = new Map<string, HTMLImageElement>()

    // 创建Intersection Observer
    const observer = new IntersectionObserver(
      entries => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            const img = entry.target as HTMLImageElement
            const src = img.dataset.src

            if (src) {
              loadImage(img, src, defaultOptions)
                .then(() => {
                  observer.unobserve(img)
                })
                .catch(() => {
                  observer.unobserve(img)
                })
            }
          }
        })
      },
      {
        rootMargin: defaultOptions.rootMargin,
      }
    )

    // 加载图片
    const loadImage = (img: HTMLImageElement, src: string, options: LazyOptions): Promise<void> => {
      return new Promise((resolve, reject) => {
        // 如果已经加载过，直接使用
        if (imageCache.has(src)) {
          img.src = src
          resolve()
          return
        }

        const image = new Image()
        let attempts = 0

        image.onload = () => {
          img.src = src
          imageCache.set(src, image)
          resolve()
        }

        image.onerror = () => {
          attempts++
          if (attempts < options.attempts!) {
            // 重试
            setTimeout(() => {
              loadImage(img, src, options).then(resolve).catch(reject)
            }, 1000 * attempts)
          } else {
            // 使用错误占位图
            img.src = options.error!
            reject(new Error(`图片加载失败: ${src}`))
          }
        }

        image.src = src
      })
    }

    // 注册指令
    app.directive('lazy', {
      mounted(el: HTMLImageElement, binding) {
        // 如果是指令形式 <img v-lazy="src">
        if (binding.value) {
          el.dataset.src = binding.value
          el.src = defaultOptions.loading!
        }

        observer.observe(el)
      },
      unmounted(el: HTMLImageElement) {
        observer.unobserve(el)
      },
      updated(el: HTMLImageElement, binding) {
        // 如果src变化，重新加载
        if (binding.value !== binding.oldValue) {
          el.dataset.src = binding.value
          if (!observer.takeRecords) {
            // 重新观察
            observer.unobserve(el)
            observer.observe(el)
          }
        }
      },
    })

    // 清理缓存的方法（供外部调用）
    app.config.globalProperties.$clearLazyCache = () => {
      imageCache.clear()
    }
  },
}
